package io.github.junxworks.qt.modules.mm.engine.handlers;

import java.util.List;

import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.github.junxworks.ep.qlexp.ExecResult;
import io.github.junxworks.ep.qlexp.RuleEngine;
import io.github.junxworks.ep.qlexp.SpringQLContext;
import io.github.junxworks.junx.core.exception.BaseRuntimeException;
import io.github.junxworks.junx.core.util.DateUtils;
import io.github.junxworks.junx.core.util.ExceptionUtils;
import io.github.junxworks.junx.event.EventChannel;
import io.github.junxworks.junx.event.EventChannelHandler;
import io.github.junxworks.junx.event.EventContext;
import io.github.junxworks.junx.stat.Stat;
import io.github.junxworks.junx.stat.StatContext;
import io.github.junxworks.junx.stat.StatDefinition;
import io.github.junxworks.junx.stat.datawindow.DataBundle;
import io.github.junxworks.junx.stat.datawindow.DataWindowConstants;
import io.github.junxworks.qt.config.Params;
import io.github.junxworks.qt.config.Topics;
import io.github.junxworks.qt.constants.QtConstants;
import io.github.junxworks.qt.modules.mm.engine.CtxHolder;
import io.github.junxworks.qt.modules.mm.engine.DataContext;
import io.github.junxworks.qt.modules.mm.engine.ExeContext;
import io.github.junxworks.qt.modules.mm.engine.cache.StatCache;
import io.github.junxworks.qt.modules.mm.engine.functions.Functions;
import io.github.junxworks.qt.modules.mm.entity.RStatResult;
import io.github.junxworks.qt.modules.mm.vo.MmVariableVo;

@Component
public class StatHandler implements EventChannelHandler {

	@Autowired
	private RuleEngine engine;

	@SuppressWarnings("rawtypes")
	@Override
	public void handleEvent(EventContext event, EventChannel channel) throws Exception {
		DataContext data = event.getData(DataContext.class, Params.DATA_CONTEXT);
		ExeContext exeContext = data.getExeContext();
		boolean onlyStat = exeContext.isOnlyStat();
		long timestamp = DateUtils.parseDate(exeContext.getTradeDate(), "yyyyMMdd").getTime();
		try {
			if (!data.isDone()) {
				StatCache statCache = data.getExeContext().getStatCache();
				String key = data.getKey().getValue();
				String column = data.getKey().getColumn();
				String tradeDate = exeContext.getTradeDate();
				//开始变量统计
				List<MmVariableVo> vs = exeContext.getVariables(column);
				for (int i = 0, len = vs.size(); i < len; i++) {
					MmVariableVo v = vs.get(i);
					try {
						String statKey = Functions.createKeyName(v.getName(), key);
						Stat stat = statCache.getStat(statKey);
						if (stat == null) {
							StatDefinition statDef = new StatDefinition();
							int type = Integer.valueOf(v.getDataWindowType());
							statDef.setDataWindowType(type);
							statDef.setStatFunction(v.getStatFunc());
							statDef.setDataWindowSize(v.getDataWindowSize());
							if (DataWindowConstants.WIN_TYPE_TIME == type) {
								statDef.setDataWindowTimeUnit(v.getTimeWindowUnit());
							} else {
								statDef.setDataWindowPriorityType(v.getPriorityStrategy());
							}
							stat = Stat.create(statDef);
							statCache.putStat(statKey, stat);
						}
						String type = v.getType();
						Object statObject = null;
						if (QtConstants.STAT_DATA_SOURCE_DS.equals(type)) {
							//数据流
							statObject = data.getDsData(v.getDsName(), v.getStatField());
						} else if (QtConstants.STAT_DATA_SOURCE_EXP.equals(type)) {
							//表达式
							SpringQLContext qlCtx = new SpringQLContext();
							qlCtx.put("exeContext", exeContext);
							qlCtx.put("交易日期", tradeDate);
							ExecResult execRes = null;
							CtxHolder.setContext(data);
							try {
								execRes = engine.execute(v.getExpression(), qlCtx);
								if (!execRes.isSuccess()) {
									throw new BaseRuntimeException(execRes.getErrorMsg());
								}
								statObject = execRes.getResult();
								if (statObject == null) {
									throw new BaseRuntimeException("指标统计表达式执行结果为空");
								}
							} catch (Throwable t) {
								throw new BaseRuntimeException("指标[" + v.getName() + "]表达式执行失败，失败原因：%s", ExceptionUtils.getCauseMessage(t));
							} finally {
								CtxHolder.remove();
							}
						}
						if (statObject instanceof List) {
							for (Object o : (List) statObject) {
								DataBundle d = new DataBundle(timestamp, o);
								stat.compose(d);
							}
						} else {
							DataBundle d = new DataBundle(timestamp, statObject);
							stat.compose(d);
						}
						StatContext ctx = new StatContext();
						ctx.setTimestamp(timestamp);
						Object resData = stat.getValue(ctx);
						Object res = ConvertUtils.convert(resData, Class.forName(v.getOutputType()));
						exeContext.putStatValue(statKey, res);
						if (exeContext.shouldExecuteExp()) {
							RStatResult mr = new RStatResult();
							mr.setKeyName(column);
							mr.setKeyValue(key);
							mr.setName(v.getName());
							//								mr.setValue(Double.valueOf(String.valueOf(res)));
							mr.setValue(String.valueOf(res));
							mr.setTradeDate(tradeDate);
							EventContext _ctx = new EventContext(Topics.STORE_STAT_RES);
							_ctx.setData(Params.PARAM_STORE_OBJ, mr);
							channel.publish(Topics.STORE_STAT_RES, _ctx);
						}
					} catch (Exception e) {
						throw new BaseRuntimeException("指标[" + v.getName() + "]执行失败，失败原因：%s", ExceptionUtils.getCauseMessage(e));
					}
				}
				if (!onlyStat && data.isStock()) {
					//股票相关才执行表达式
					EventContext ctx = new EventContext(Topics.EXPRESSION);
					ctx.setData(Params.DATA_CONTEXT, data);
					channel.publish(Topics.EXPRESSION, ctx);
				} else {
					data.done();
				}
			}
		} catch (Throwable e) {
			data.setException(e);
		}
	}

}
